package com.gzc.just.play.last.war.sceneserver.service;

import com.gzc.just.play.last.war.sceneserver.entity.Player;
import com.gzc.just.play.last.war.sceneserver.entity.PlayerAttribute;
import com.gzc.just.play.last.war.sceneserver.repository.PlayerAttributeRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * 玩家属性服务类
 * 
 * 提供玩家属性相关的业务逻辑
 * 作为Phase 4.3数据库持久化集成的一部分
 */
@Service
@Transactional
public class PlayerAttributeService {
    
    private static final Logger logger = LoggerFactory.getLogger(PlayerAttributeService.class);
    
    @Autowired
    private PlayerAttributeRepository playerAttributeRepository;
    
    /**
     * 创建玩家属性
     */
    public PlayerAttribute createAttribute(Player player, int attributeType, int baseValue) {
        // 检查是否已存在该属性
        Long playerId = player.getPlayerId();
        Optional<PlayerAttribute> existingAttribute = playerAttributeRepository
                .findByPlayerIdAndAttributeType(playerId, attributeType);
        
        if (existingAttribute.isPresent()) {
            logger.warn("Player attribute already exists: PlayerID={}, AttributeType={}", playerId, attributeType);
            return existingAttribute.get();
        }
        
        PlayerAttribute attribute = new PlayerAttribute(player, attributeType, baseValue);
        attribute = playerAttributeRepository.save(attribute);
        
        logger.info("Created player attribute: PlayerID={}, AttributeType={}, BaseValue={}", 
                playerId, attributeType, baseValue);
        
        return attribute;
    }
    
    /**
     * 根据玩家ID和属性类型获取属性
     */
    @Cacheable(value = "player-attributes", key = "#playerId + '-' + #attributeType")
    @Transactional(readOnly = true)
    public Optional<PlayerAttribute> getAttribute(Long playerId, int attributeType) {
        return playerAttributeRepository.findByPlayerIdAndAttributeType(playerId, attributeType);
    }
    
    /**
     * 获取玩家的所有属性
     */
    @Cacheable(value = "player-attributes", key = "#playerId")
    @Transactional(readOnly = true)
    public List<PlayerAttribute> getPlayerAttributes(Long playerId) {
        return playerAttributeRepository.findByPlayerId(playerId);
    }
    
    /**
     * 更新玩家属性
     */
    @CacheEvict(value = "player-attributes", key = "#playerId + '-' + #attributeType")
    public PlayerAttribute updateAttributeValue(Long playerId, int attributeType, int newValue) {
        PlayerAttribute attribute = playerAttributeRepository
                .findByPlayerIdAndAttributeType(playerId, attributeType)
                .orElseThrow(() -> new RuntimeException("Player attribute not found: PlayerID=" + playerId + ", AttributeType=" + attributeType));
        
        attribute.setCurrentValue(newValue);
        attribute = playerAttributeRepository.save(attribute);
        
        logger.info("Updated player attribute: PlayerID={}, AttributeType={}, NewValue={}", playerId, attributeType, newValue);
        
        return attribute;
    }
    
    /**
     * 调整玩家属性值（增加或减少）
     */
    @CacheEvict(value = "player-attributes", key = "#playerId + '-' + #attributeType")
    public PlayerAttribute adjustAttributeValue(Long playerId, int attributeType, int adjustment) {
        PlayerAttribute attribute = playerAttributeRepository
                .findByPlayerIdAndAttributeType(playerId, attributeType)
                .orElseThrow(() -> new RuntimeException("Player attribute not found: PlayerID=" + playerId + ", AttributeType=" + attributeType));
        
        attribute.adjustCurrentValue(adjustment);
        
        // 如果是生命值或法力值，不能超过最大值
        if (attributeType == PlayerAttribute.ATTRIBUTE_TYPE_HEALTH) {
            Optional<PlayerAttribute> maxHealthAttr = playerAttributeRepository
                    .findByPlayerIdAndAttributeType(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MAX_HEALTH);
            if (maxHealthAttr.isPresent() && attribute.getCurrentValue() > maxHealthAttr.get().getCurrentValue()) {
                attribute.setCurrentValue(maxHealthAttr.get().getCurrentValue());
            }
        } else if (attributeType == PlayerAttribute.ATTRIBUTE_TYPE_MANA) {
            Optional<PlayerAttribute> maxManaAttr = playerAttributeRepository
                    .findByPlayerIdAndAttributeType(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MAX_MANA);
            if (maxManaAttr.isPresent() && attribute.getCurrentValue() > maxManaAttr.get().getCurrentValue()) {
                attribute.setCurrentValue(maxManaAttr.get().getCurrentValue());
            }
        }
        
        // 确保属性值不为负数
        if (attribute.getCurrentValue() < 0) {
            attribute.setCurrentValue(0);
        }
        
        attribute = playerAttributeRepository.save(attribute);
        
        logger.debug("Adjusted player attribute: PlayerID={}, AttributeType={}, Adjustment={}, CurrentValue={}", 
                playerId, attributeType, adjustment, attribute.getCurrentValue());
        
        return attribute;
    }
    
    /**
     * 将属性值恢复到基础值
     */
    @CacheEvict(value = "player-attributes", key = "#playerId + '-' + #attributeType")
    public PlayerAttribute resetAttributeToBase(Long playerId, int attributeType) {
        PlayerAttribute attribute = playerAttributeRepository
                .findByPlayerIdAndAttributeType(playerId, attributeType)
                .orElseThrow(() -> new RuntimeException("Player attribute not found: PlayerID=" + playerId + ", AttributeType=" + attributeType));
        
        attribute.resetToBase();
        attribute = playerAttributeRepository.save(attribute);
        
        logger.info("Reset player attribute to base value: PlayerID={}, AttributeType={}", playerId, attributeType);
        
        return attribute;
    }
    
    /**
     * 将属性恢复到最大值
     */
    @CacheEvict(value = "player-attributes", key = "#playerId + '-' + #attributeType")
    public PlayerAttribute resetAttributeToMax(Long playerId, int attributeType) {
        PlayerAttribute attribute = playerAttributeRepository
                .findByPlayerIdAndAttributeType(playerId, attributeType)
                .orElseThrow(() -> new RuntimeException("Player attribute not found: PlayerID=" + playerId + ", AttributeType=" + attributeType));
        
        // 对于非最大值属性，恢复到基础值
        if (attributeType == PlayerAttribute.ATTRIBUTE_TYPE_HEALTH) {
            Optional<PlayerAttribute> maxHealthAttr = playerAttributeRepository
                    .findByPlayerIdAndAttributeType(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MAX_HEALTH);
            if (maxHealthAttr.isPresent()) {
                attribute.setCurrentValue(maxHealthAttr.get().getCurrentValue());
            }
        } else if (attributeType == PlayerAttribute.ATTRIBUTE_TYPE_MANA) {
            Optional<PlayerAttribute> maxManaAttr = playerAttributeRepository
                    .findByPlayerIdAndAttributeType(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MAX_MANA);
            if (maxManaAttr.isPresent()) {
                attribute.setCurrentValue(maxManaAttr.get().getCurrentValue());
            }
        } else {
            attribute.resetToBase();
        }
        
        attribute = playerAttributeRepository.save(attribute);
        
        logger.info("Reset player attribute to maximum value: PlayerID={}, AttributeType={}", playerId, attributeType);
        
        return attribute;
    }
    
    /**
     * 更新属性基础值
     */
    @CacheEvict(value = "player-attributes", key = "#playerId + '-' + #attributeType")
    public PlayerAttribute updateAttributeBaseValue(Long playerId, int attributeType, int newBaseValue) {
        PlayerAttribute attribute = playerAttributeRepository
                .findByPlayerIdAndAttributeType(playerId, attributeType)
                .orElseThrow(() -> new RuntimeException("Player attribute not found: PlayerID=" + playerId + ", AttributeType=" + attributeType));
        
        attribute.setBaseValue(newBaseValue);
        attribute = playerAttributeRepository.save(attribute);
        
        logger.info("Updated player attribute base value: PlayerID={}, AttributeType={}, NewBaseValue={}", 
                playerId, attributeType, newBaseValue);
        
        return attribute;
    }
    
    /**
     * 批量更新玩家属性
     */
    @CacheEvict(value = "player-attributes", key = "#playerId")
    public List<PlayerAttribute> updatePlayerAttributes(Long playerId, List<PlayerAttribute> attributes) {
        // 验证所有属性都属于该玩家
        for (PlayerAttribute attr : attributes) {
            if (!attr.getPlayer().getPlayerId().equals(playerId)) {
                throw new RuntimeException("Attribute does not belong to specified player: PlayerID=" + playerId + ", AttributePlayerID=" + 
                        attr.getPlayer().getPlayerId());
            }
        }
        
        List<PlayerAttribute> savedAttributes = playerAttributeRepository.saveAll(attributes);
        
        logger.info("Batch updated player attributes: PlayerID={}, AttributeCount={}", playerId, attributes.size());
        
        return savedAttributes;
    }
    
    /**
     * 获取玩家当前生命值
     */
    @Transactional(readOnly = true)
    public int getPlayerHealth(Long playerId) {
        Optional<PlayerAttribute> healthAttr = getAttribute(playerId, PlayerAttribute.ATTRIBUTE_TYPE_HEALTH);
        return healthAttr.map(PlayerAttribute::getCurrentValue).orElse(0);
    }
    
    /**
     * 获取玩家最大生命值
     */
    @Transactional(readOnly = true)
    public int getPlayerMaxHealth(Long playerId) {
        Optional<PlayerAttribute> maxHealthAttr = getAttribute(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MAX_HEALTH);
        return maxHealthAttr.map(PlayerAttribute::getCurrentValue).orElse(0);
    }
    
    /**
     * 获取玩家当前法力值
     */
    @Transactional(readOnly = true)
    public int getPlayerMana(Long playerId) {
        Optional<PlayerAttribute> manaAttr = getAttribute(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MANA);
        return manaAttr.map(PlayerAttribute::getCurrentValue).orElse(0);
    }
    
    /**
     * 获取玩家最大法力值
     */
    @Transactional(readOnly = true)
    public int getPlayerMaxMana(Long playerId) {
        Optional<PlayerAttribute> maxManaAttr = getAttribute(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MAX_MANA);
        return maxManaAttr.map(PlayerAttribute::getCurrentValue).orElse(0);
    }
    
    /**
     * 获取玩家攻击力
     */
    @Transactional(readOnly = true)
    public int getPlayerAttack(Long playerId) {
        Optional<PlayerAttribute> attackAttr = getAttribute(playerId, PlayerAttribute.ATTRIBUTE_TYPE_ATTACK);
        return attackAttr.map(PlayerAttribute::getCurrentValue).orElse(0);
    }
    
    /**
     * 获取玩家防御力
     */
    @Transactional(readOnly = true)
    public int getPlayerDefense(Long playerId) {
        Optional<PlayerAttribute> defenseAttr = getAttribute(playerId, PlayerAttribute.ATTRIBUTE_TYPE_DEFENSE);
        return defenseAttr.map(PlayerAttribute::getCurrentValue).orElse(0);
    }
    
    /**
     * 检查玩家是否存活
     */
    @Transactional(readOnly = true)
    public boolean isPlayerAlive(Long playerId) {
        int health = getPlayerHealth(playerId);
        int maxHealth = getPlayerMaxHealth(playerId);
        return maxHealth > 0 && health > 0;
    }
    
    /**
     * 造成伤害给玩家
     */
    public int damagePlayer(Long playerId, int damage) {
        if (damage <= 0) {
            return 0;
        }
        
        int currentHealth = getPlayerHealth(playerId);
        int defense = getPlayerDefense(playerId);
        
        // 计算实际伤害：伤害 - 防御力，最低造成1点伤害
        int actualDamage = Math.max(1, damage - defense);
        int newHealth = Math.max(0, currentHealth - actualDamage);
        
        updateAttributeValue(playerId, PlayerAttribute.ATTRIBUTE_TYPE_HEALTH, newHealth);
        
        logger.info("Player took damage: PlayerID={}, Damage={}, Defense={}, ActualDamage={}, RemainingHealth={}", 
                playerId, damage, defense, actualDamage, newHealth);
        
        return actualDamage;
    }
    
    /**
     * 治疗玩家
     */
    public int healPlayer(Long playerId, int healAmount) {
        if (healAmount <= 0) {
            return 0;
        }
        
        int currentHealth = getPlayerHealth(playerId);
        int maxHealth = getPlayerMaxHealth(playerId);
        
        // 计算实际治疗量：不能超过最大生命值
        int actualHeal = Math.min(healAmount, maxHealth - currentHealth);
        int newHealth = currentHealth + actualHeal;
        
        updateAttributeValue(playerId, PlayerAttribute.ATTRIBUTE_TYPE_HEALTH, newHealth);
        
        logger.info("Player healed: PlayerID={}, HealAmount={}, ActualHeal={}, CurrentHealth={}/{}/{}", 
                playerId, healAmount, actualHeal, newHealth, maxHealth);
        
        return actualHeal;
    }
    
    /**
     * 消耗玩家法力值
     */
    public boolean consumeMana(Long playerId, int manaCost) {
        int currentMana = getPlayerMana(playerId);
        
        if (currentMana < manaCost) {
            return false;
        }
        
        updateAttributeValue(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MANA, currentMana - manaCost);
        
        logger.debug("Player consumed mana: PlayerID={}, Consumed={}, CurrentMana={}", playerId, manaCost, currentMana - manaCost);
        
        return true;
    }
    
    /**
     * 恢复玩家法力值
     */
    public int restoreMana(Long playerId, int manaAmount) {
        if (manaAmount <= 0) {
            return 0;
        }
        
        int currentMana = getPlayerMana(playerId);
        int maxMana = getPlayerMaxMana(playerId);
        
        // 计算实际恢复量：不能超过最大法力值
        int actualRestore = Math.min(manaAmount, maxMana - currentMana);
        int newMana = currentMana + actualRestore;
        
        updateAttributeValue(playerId, PlayerAttribute.ATTRIBUTE_TYPE_MANA, newMana);
        
        logger.debug("Player restored mana: PlayerID={}, RestoreAmount={}, ActualRestore={}, CurrentMana={}/{}/{}", 
                playerId, manaAmount, actualRestore, newMana, maxMana);
        
        return actualRestore;
    }
}